/*
  Copyright © 2010  Vinícius dos Santos Oliveira

      This file is part of Touché.

      Touché is free software: you can redistribute it and/or modify
      it under the terms of the GNU Lesser General Public License as published
      by the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.

      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU Lesser General Public License for more details.

      You should have received a copy of the GNU Lesser General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */

#include "draggabletogglebutton.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
#include <QApplication>
#include <QDebug>
#include <QPropertyAnimation>

enum Pallete
{
    NORMAL,
    ACTIVED
};

static int startDragDistance = QApplication::startDragDistance();

QList<DraggableToggleButton *> DraggableToggleButton::m_buttons;

DraggableToggleButton::DraggableToggleButton() :
        m_boundingRect(0., 0., 0., 0.),
        checked(false),
        pen(QBrush(QColor(240, 206, 17)), 4.),
        doubleClickEmitted(false)
{
    pallete[NORMAL] = QColor(240, 206, 17);
    pallete[ACTIVED] = QColor(248, 224, 20);
    setCacheMode(DeviceCoordinateCache);
    m_buttons.push_back(this);
}

DraggableToggleButton::~DraggableToggleButton()
{
    for(QList<DraggableToggleButton *>::iterator i(m_buttons.begin());i != m_buttons.end();++i){
        if(*i == this){
            m_buttons.erase(i);
            break;
        }
    }
}

void DraggableToggleButton::updateBoundingRect(const QRectF &boundingRect)
{
    QGraphicsItem::prepareGeometryChange();
    m_boundingRect.setSize(boundingRect.size());
    m_boundingRect.moveTopLeft(QPointF(14., 14.));
    m_boundingRect.setTopLeft(QPointF(-14., -14.));

    m_paintBoundingRect = QRectF(m_boundingRect.left() + 2,
                                 m_boundingRect.top() + 2,
                                 m_boundingRect.width() - 4,
                                 m_boundingRect.height() - 4);
}

QRectF DraggableToggleButton::boundingRect() const
{
    return m_boundingRect;
}

void DraggableToggleButton::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
    painter->setPen(pen);
    painter->drawEllipse(m_paintBoundingRect);
}

QPainterPath DraggableToggleButton::shape() const
{
    QPainterPath path;
    path.addEllipse(m_boundingRect);
    return path;
}

bool DraggableToggleButton::isChecked() const
{
    return checked;
}

void DraggableToggleButton::setColor(const QColor &normal, const QColor &actived)
{
    pallete[NORMAL] = normal;
    pallete[ACTIVED] = actived;
    if(checked)
        pen.setColor(actived);
    else
        pen.setColor(normal);
    QGraphicsItem::update();
}

void DraggableToggleButton::setChecked(bool checked)
{
    if(this->checked != checked){
        emit toggled(this->checked = checked);
        if(checked)
            pen.setColor(pallete[ACTIVED]);
        else
            pen.setColor(pallete[NORMAL]);
        QGraphicsItem::update();
    }
}

void DraggableToggleButton::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    event->accept();
    emit pressed();
    pressedAt = event->screenPos();
    lastPos = QGraphicsItem::pos();

    pen.setColor(pallete[ACTIVED]);
    QGraphicsObject::update();
}

void DraggableToggleButton::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    if(QGraphicsObject::flags() & QGraphicsObject::ItemIsMovable){
        QGraphicsObject::setPos(QGraphicsObject::pos() + (1. / QGraphicsObject::scale()) *
                                 (event->pos() - event->lastPos()));
    }
}

void DraggableToggleButton::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    //TODO: verify if double click was already emitted
    if(doubleClickEmitted){
        doubleClickEmitted = false;
        return;
    }
    emit release();

    if((pressedAt - event->screenPos()).manhattanLength() < startDragDistance){
        // click

        emit toggled(checked = !checked);
        if(checked) {
            pen.setColor(pallete[ACTIVED]);
        }
        QGraphicsItem::update();
    }else{
        //move

        QList<QGraphicsItem *> items = QGraphicsItem::collidingItems();
        if(!items.isEmpty()){
            for(QListIterator<QGraphicsItem *> i(items);i.hasNext();){
                if(DraggableToggleButton *item = dynamic_cast<DraggableToggleButton *>(i.next())){
                    QPropertyAnimation *animation = new QPropertyAnimation(this, "pos");
                    animation->setDuration(500);
                    animation->setEndValue(lastPos);
                    animation->setEasingCurve(QEasingCurve::OutQuart);

                    emit dragged(item);

                    animation->start(QAbstractAnimation::DeleteWhenStopped);
                    break;
                }
            }
        }
    }

    if(!checked){
        pen.setColor(pallete[NORMAL]);
        QGraphicsObject::update();
    }
}

void DraggableToggleButton::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
{
    doubleClickEmitted = true;
    emit doubleClicked();
}

const QList<DraggableToggleButton *> &DraggableToggleButton::buttons()
{
    return m_buttons;
}
